package xin.marcher.module.diplomacy.api.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import xin.marcher.module.common.constants.diplomacy.AbstractRedisKeyConstants;
import xin.marcher.module.common.core.JsonResult;
import xin.marcher.module.common.exception.ProductErrorCodeEnum;
import xin.marcher.module.common.utils.ParamCheckUtil;
import xin.marcher.module.diplomacy.api.ProductSaleApi;
import xin.marcher.module.diplomacy.domain.dto.ProductSaleCollectDTO;
import xin.marcher.module.diplomacy.domain.dto.ProductSaleRelationDTO;
import xin.marcher.module.diplomacy.domain.query.ProductSaleQuery;
import xin.marcher.module.diplomacy.domain.query.ProductSaleRelationQuery;
import xin.marcher.module.diplomacy.manager.custom.cache.SkuSellerCache;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static xin.marcher.module.common.constants.diplomacy.BaseConstants.PAGE_NO_1;
import static xin.marcher.module.common.constants.diplomacy.BaseConstants.PAGE_SIZE_1000;

/**
 * 商品售卖服务
 */
@Slf4j
@DubboService(version = "1.0.0", interfaceClass = ProductSaleApi.class, retries = 0)
public class ProductSaleApiImpl implements ProductSaleApi {

    @Resource
    private SkuSellerCache skuSellerCache;

    /**
     * 分页查询卖家类型下的可售商品
     *
     * @param productSaleQuery
     * @return xin.marcher.module.common.core.JsonResult<xin.marcher.module.diplomacy.domain.dto.ProductSaleDTO>
     */
    @Override
    public JsonResult<ProductSaleCollectDTO> getSaleSkuByPage(ProductSaleQuery productSaleQuery) {
        checkSaleSkuByPageParams(productSaleQuery);

        int pageNo = PAGE_NO_1;
        int pageSize = PAGE_SIZE_1000;
        if (Objects.nonNull(productSaleQuery.getPageNo())) {
            pageNo = productSaleQuery.getPageNo();
        }
        if (Objects.nonNull(productSaleQuery.getPageSize())) {
            pageSize = productSaleQuery.getPageSize();
        }
        int offset = (pageNo - 1) * pageSize;

        String redisKey = AbstractRedisKeyConstants.getSellerTypeSaleSkuZsetKey(productSaleQuery.getSellerType());
        Optional<List<String>> optional = skuSellerCache.listRedisSortedSetData(productSaleQuery.getSellerType(),
                offset, pageSize, AbstractRedisKeyConstants::getSellerTypeSaleSkuZsetKey);
        if (!optional.isPresent()) {
            return JsonResult.buildError(ProductErrorCodeEnum.NO_RESULT_ERROR);
        }

        boolean nextPage = false;
        Long count = skuSellerCache.zcard(redisKey);
        if (count.intValue() > (offset + pageSize)) {
            nextPage = true;
        }

        ProductSaleCollectDTO productSaleCollectDTO = new ProductSaleCollectDTO();
        productSaleCollectDTO.setSkuIdList(optional.get());
        productSaleCollectDTO.setNextPage(nextPage);
        productSaleCollectDTO.setTotal(count);
        return JsonResult.buildSuccess(productSaleCollectDTO);
    }

    /**
     * 参数校验
     *
     * @param productSaleQuery
     */
    private void checkSaleSkuByPageParams(ProductSaleQuery productSaleQuery) {
        ParamCheckUtil.checkObjectNonNull(productSaleQuery);
        ParamCheckUtil.checkIntegerNonEmpty(productSaleQuery.getSellerType());
        ParamCheckUtil.checkIntegerNonEmpty(productSaleQuery.getPageNo());
        ParamCheckUtil.checkIntegerNonEmpty(productSaleQuery.getPageSize());
    }

    /**
     * 根据卖家ID查询可售商品列表
     *
     * @param sellerId
     * @return xin.marcher.module.common.core.JsonResult<java.util.List < java.lang.String>>
     */
    @Override
    public JsonResult<List<String>> getSaleSkuBySellerId(Long sellerId) {
        // 直接获取卖家的可售商品缓存信息
        Optional<List<String>> optional = skuSellerCache.listRedisSortedSetData(sellerId, 0, -1,
                AbstractRedisKeyConstants::getSellerSaleSkuZsetKey);
        return optional.map(JsonResult::buildSuccess).orElseGet(() -> JsonResult.buildError(ProductErrorCodeEnum.NO_RESULT_ERROR));
    }

    /**
     * 根据卖家ID和商品编码判断商品是否可售
     *
     * @param productSaleRelationQuery
     * @return xin.marcher.module.common.core.JsonResult<xin.marcher.module.diplomacy.domain.dto.ProductSaleRelationDTO>
     */
    @Override
    public JsonResult<ProductSaleRelationDTO> checkSaleSku(ProductSaleRelationQuery productSaleRelationQuery) {
        // 参数校验
        checkSaleSkuParams(productSaleRelationQuery);

        List<Long> sellerIdList = productSaleRelationQuery.getSellerIdList();

        // 获取卖家可售商品集合
        Optional<Map<Long, List<String>>> optional = skuSellerCache.queryRedisSortedSetDataMap(sellerIdList,
                AbstractRedisKeyConstants::getSellerSaleSkuZsetKey);

        if (!optional.isPresent()) {
            return JsonResult.buildSuccess();
        }

        // 构建可售商品和卖家关系,以及不可售商品列表
        ProductSaleRelationDTO productSaleRelationDTO = buildProductSaleRelation(optional.get(),
                productSaleRelationQuery.getProductIdList());
        return JsonResult.buildSuccess(productSaleRelationDTO);
    }

    /**
     * 处理商品是否可售
     *
     * @param skuIdMap
     * @param productIdList
     * @return
     */
    private ProductSaleRelationDTO buildProductSaleRelation(Map<Long, List<String>> skuIdMap,
                                                            Set<String> productIdList) {

        List<String> notSaleProductIds = new ArrayList<>(productIdList.size());
        notSaleProductIds.addAll(productIdList);

        Map<Long, List<String>> sellerSaleProductIds = new HashMap<>(skuIdMap.size());
        for (Map.Entry<Long, List<String>> entry : skuIdMap.entrySet()) {
            List<String> saleProductIds = entry.getValue();

            // 当前卖家可售商品
            List<String> skuIds = saleProductIds.stream().filter(productIdList::contains).collect(Collectors.toList());
            sellerSaleProductIds.put(entry.getKey(), skuIds);

            // 已经可售的商品，在不可售的商品中移除
            notSaleProductIds.removeAll(skuIds);
        }

        return new ProductSaleRelationDTO(sellerSaleProductIds, notSaleProductIds);

    }

    /**
     * 参数校验
     *
     * @param productSaleRelationQuery
     */
    private void checkSaleSkuParams(ProductSaleRelationQuery productSaleRelationQuery) {
        ParamCheckUtil.checkObjectNonNull(productSaleRelationQuery);
        ParamCheckUtil.checkCollectionNonEmpty(productSaleRelationQuery.getProductIdList());
        ParamCheckUtil.checkCollectionNonEmpty(productSaleRelationQuery.getSellerIdList());
    }


}
